<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <script type="module">

        // const obj = {
        //     toString() {
        //         return "szq";
        //     }
        // }
        // const sym = Symbol(obj);
        // const sym2=Symbol(obj);
        // console.log(sym);
        // console.log(sym2);
        // console.log(sym==sym2);
        // console.log(sym===sym2);
        // console.log(sym.description);
        // console.log(sym2.description);

        // // 作为属性名的 Symbol

        // let myproperty=Symbol("pt");
        // const myobj={};
        // myobj[myproperty]="szq";
        // console.log(myobj);
        // const myobj={};
        // Reflect.defineProperty(myobj,[myproperty],{value:'szq',writable:true,configurable:{}})

        // *****************Symbol 值作为属性名，遍历对象的时候，
        // // 该属性不会出现在for...in、for...of循环中，
        // // 也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

        // let obj = { "p3": "3" };
        // let p1 = Symbol("p1");
        // let p2 = Symbol("p2");
        // let m1 = Symbol("m1");

        // obj[p1] = "1";
        // obj[p2] = "2";
        // obj[m1] = (value) => { return value; }
        // obj["p4"] = "4";

        // // configurable:false --->>不能用delete删除属性，不能重新定义该属性
        // // writable:false ---->>表示能否修改该属性，默认值是false，默认情况下，不能再更改该属性的值。
        // Reflect.defineProperty(obj, "p5", { value: "5", enumerable: true, configurable: true, writable: true });
        // Reflect.defineProperty(obj, "p6", { value: "6", enumerable: true, configurable: true, writable: true });
        // // // 能看见Symbol属性
        // // console.log(Object.getOwnPropertyDescriptors(obj));


        // 在javascript中，
        // for in是ES5标准，遍历key. 
        // for of是ES6标准，遍历value.

        // 1.使用for-in会遍历数组所有的可枚举属性，包括原型。
        // 通常需要配合hasOwnProperty()方法判断某个属性是否该对象的实例属性，来将原型对象从循环中剔除。

        // 2.自ES5发布后也可以使用forEach来遍历数组，forEach仅遍历写在方括号里面的元素，且
        // 可以同时对key和value操作，key的类型为number

        // 注：在for、for-in中，break和continue可以正常执行并且达到想到的结果，但是return 不能正常执行。
        // 在forEach、map、filter中break和continue不能正常执行，return仅仅跳出当前循环，不会跳出整个函数。

        // 3，for-of可以简单、正确地遍历数组，这是最简洁、最直接的遍历数组元素的语法。
        // 完美地避开了for-in循环的所有缺陷。与forEach()不同的是，它可以正确响应break、continue和return语句。

        // // for...in语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性，语句都会被执行。
        // for (let item in obj) {
        //     console.log(obj[item]);
        // }

        // // for...of语句在可迭代对象（包括 Array，Map，Set，String，TypedArray，arguments 对象等等）上创建一个迭代循环，调用自定义迭代钩子，并为每个不同属性的值执行语句
        // // 由此概念可看出区别：for..in是返回可枚举对象的属性，而for..of是返回可枚举对象的值
        // // Reflect.ownKeys返回一个数组，包含对象自身的（不含继承的）所有键名，不管键名是 Symbol 或字符串，也不管是否可枚举。
        // for (let item of Reflect.ownKeys(obj)) { // 这样就可以遍历 Symbol值
        //     console.log(obj[item]);
        // }
        // console.log(Reflect.getOwnPropertyDescriptor(obj, "p4"));

        // *****************内置的 Symbol 值

        // Symbol.hasInstance
        // 对象的Symbol.hasInstance属性，指向一个内部方法。当其他对象使用instanceof运算符，判断是否为该对象的实例时，会调用这个方法。比如，foo instanceof Foo在语言内部，实际调用的是Foo[Symbol.hasInstance](foo)。
        // class MyClass {
        //    static [Symbol.hasInstance](obj) {
        //         if (obj instanceof Object) {
        //             return true;
        //         }
        //     }

        // }
        // let obj = new MyClass();

        // console.log(obj instanceof MyClass);

        // class MyClass {
        //     [Symbol.hasInstance](obj) {
        //         if (obj instanceof Object) {
        //             return true;
        //         }
        //     }

        // }
        // let obj = new MyClass();

        // console.log(obj instanceof new MyClass());

        // const myClass={
        //     [Symbol.hasInstance](obj){
        //         if (obj instanceof Object){
        //             return true;
        //         }
        //     }
        // }
        // let obj=new Object();
        // console.log(obj instanceof myClass)


        // Symbol.isConcatSpreadable
        // 对象的Symbol.isConcatSpreadable属性等于一个布尔值，表示该对象用于Array.prototype.concat()时，是否可以展开。

        // let arry1=["1","2"];
        // let arry2=["3","4"].concat(arry1,...["6","7"]);
        // console.log(arry1[Symbol.isConcatSpreadable]);
        // console.log(arry2);//['3', '4', '1', '2', '6', '7']

        // let arry1 = ["1", "2"];
        // arry1[Symbol.isConcatSpreadable] = false;
        // let arry2 = ["3", "4"];
        // arry2[Symbol.isConcatSpreadable] = false;
        // let array3 = arry2.concat(arry1, ...["6", "7"]);
        // console.log(arry1);// ['1', '2', Symbol(Symbol.isConcatSpreadable): false]
        // console.log(arry2);// ['3', '4', Symbol(Symbol.isConcatSpreadable): false]
        // console.log(array3);//[['3', '4'], ['1', '2'], '6', '7']

        // 类似数组的对象正好相反，默认不展开。它的Symbol.isConcatSpreadable属性设为true，才可以展开。

        // let obj = { length: 2, 0: "1", 1: "2" };
        // let arry1 = ["3", "4"].concat(obj);
        // console.log(arry1); // ['3', '4', {length: 2, 0: '1', 1: '2'}]

        // let obj = { length: 2, 0: "1", 1: "2" };
        // obj[Symbol.isConcatSpreadable] = true;
        // let arry1 = ["3", "4"].concat(obj,"5");
        // console.log(arry1); // ['3', '4', '1', '2', '5']

        // Symbol.isConcatSpreadable属性也可以定义在类里面

        // class MyClass1 extends Array {

        //     constructor() {
        //         super();
        //         this[Symbol.isConcatSpreadable] = true;
        //     }

        // }
        // class MyClass2 extends Array {

        //     constructor() {
        //         super();
        //         this[Symbol.isConcatSpreadable] = false;
        //     }
        // }
        // let myobjarray1 = new MyClass1();
        // myobjarray1.push("1");
        // myobjarray1.push("2");
        // let myobjarray2 = new MyClass2();
        // myobjarray2.push("3");
        // myobjarray2.push("4");

        // let myobjarray3=myobjarray1.concat(myobjarray2);
        // console.log(myobjarray3); //MyClass1(3) ['1', '2', MyClass2(2), Symbol(Symbol.isConcatSpreadable): true]

        // Symbol.species § ⇧
        // 对象的Symbol.species属性，指向一个构造函数。创建衍生对象时，会使用该属性。

        // class T1 extends Promise {
        // }

        // class T2 extends Promise {
        //     static get [Symbol.species]() {
        //         return Promise;
        //     }
        // }

        // console.log(new T1(r => r()).then(v => v) instanceof T1); // true
        // console.log(new T1(r => r()).then(v => v) instanceof Promise); // true
        // console.log(new T2(r => r()).then(v => v) instanceof T2); // false

        // Symbol.match
        // 对象的Symbol.match属性，指向一个函数。当执行str.match(myObject)时，如果该属性存在，会调用它，返回该方法的返回值。
        //  class MyMatcher {
        // [Symbol.match](string) {
        //     return 'hello world'.indexOf(string);
        // }
        // }

        // 'e'.match(new MyMatcher()) // 1

        //Symbol.replace
        // 对象的Symbol.replace属性，指向一个方法，当该对象被String.prototype.replace方法调用时，会返回该方法的返回值。
        // String.prototype.replace(searchValue, replaceValue)
        // // 等同于
        // searchValue[Symbol.replace](this, replaceValue)

        const sss = (...x) => { // x =["a","b"]
            console.log(x);
        }

        sss("a", "b");

        const x = {};
        x[Symbol.replace] = (...s) => {
            console.log(s);
        }

        x[Symbol.replace]('Hello', 'World');
        x[Symbol.replace].apply(x, ['Hello', 'World']);
        'Hello'.replace(x, 'World') // ["Hello", "World"]

        'Hello'.replace('e', 'World');

    //.......//.......//.......//.......//.......
// Symbol.search
// 对象的Symbol.search属性，指向一个方法，当该对象被String.prototype.search方法调用时，会返回该方法的返回值。
// Symbol.split
// 对象的Symbol.split属性，指向一个方法，当该对象被String.prototype.split方法调用时，会返回该方法的返回值。

    </script>
</head>

<body>

</body>

</html>